
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "examples.h"
#include "xrn_crypto.h"
#include "xrn_core.h"
#include "lorem_ipsum.h"

    /////////////////////////////////////////////////////
    //                   Introduction                  //
    /////////////////////////////////////////////////////
    // This code example shows how to proof ownership  //
    // of a symmetric or asymmetric signature, without // 
    // revealing the monomial key.                     //
    /////////////////////////////////////////////////////

    /////////////////////////////////////////////////////
    //                   Pre-requisits                 //
    /////////////////////////////////////////////////////
    // The Xoron matrix decompressed data structure    //
    // needs to be mined before running this code      //
    // example. Some examples on how to mine Xoron     //
    // matrices can be found in                        //
    // generate_xrn_matrix_all_rnd.c or                //
    // generate_xrn_matrix_one_third.c                 //
    //                                                 //
    // One monomial key, and one binomial key.         //
    //                                                 //
    // An example on how to generate keys can be found //
    // in generate_keys_with_wrapper_functions.c       //
    /////////////////////////////////////////////////////

int generate_keys_and_signatures_bytes(
 )
{

    FILE *start_point_fp;
    FILE *monomial_key_fp;
    FILE *binomial_key_fp;
    FILE *decompressed_xrn_matrix_fp;
    FILE *signature_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    /////////////////////////////
    // Variable initialization //
    /////////////////////////////

    // Initialize default run time settings
    // In this code example only the settings.rnd_str is used
    // In the xrn_load_default_settings function xrn_make_start_point string is used.
    // Other functions names can be also used to initialize settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    /////////////////
    // Start point //
    /////////////////

    printf( "making start point ...\n" );

    start_point_fp = fopen( "start_point.xf", "wb" );
    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    if ( ( start_point_fp == NULL ) || ( decompressed_xrn_matrix_fp == NULL ) ) {
        return -1;
    }

    if ( XSUCCESS != xrn_make_start_point_wrapper( start_point_fp, decompressed_xrn_matrix_fp, settings ) ) {
        fclose( decompressed_xrn_matrix_fp );
        fclose( start_point_fp );
        return -1;
    }

    if ( ( 0 != fclose( start_point_fp ) ) || ( 0 != fclose( decompressed_xrn_matrix_fp ) ) ) {
        return -1;
    }

    //////////////////
    // Monomial key //
    //////////////////

    printf( "making monomial key ...\n" );

    monomial_key_fp = fopen( "monomial_key.xf", "wb" );
    if ( monomial_key_fp == NULL ) {
        return -1;
    }

    if ( XSUCCESS != xrn_make_monomial_key_wrapper( monomial_key_fp, settings ) ) {
        fclose( monomial_key_fp );
        return -1;
    }

    if ( 0 != fclose( monomial_key_fp ) ) {
        return -1;
    }

    //////////////////
    // Binomial key //
    //////////////////

    printf( "making binomial key ...\n" );

    start_point_fp = fopen( "start_point.xf", "rb" );
    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    monomial_key_fp = fopen( "monomial_key.xf", "rb" );
    binomial_key_fp = fopen( "binomial_key.xf", "wb" );

    if ( ( start_point_fp == NULL ) || ( decompressed_xrn_matrix_fp == NULL ) || ( monomial_key_fp == NULL )
         || ( binomial_key_fp == NULL ) ) {
        return -1;
    }

    if ( XSUCCESS !=
         xrn_make_binomial_key_wrapper( decompressed_xrn_matrix_fp, start_point_fp, monomial_key_fp,
                                        binomial_key_fp, settings ) ) {
        fclose( binomial_key_fp );
        fclose( decompressed_xrn_matrix_fp );
        fclose( monomial_key_fp );
        fclose( start_point_fp );
        return -1;
    }

    if ( ( 0 != fclose( start_point_fp ) ) || ( 0 != fclose( binomial_key_fp ) ) ) {
        return -1;
    }

    ////////////////////////////////////
    // Symmetric Signature Generation //
    ////////////////////////////////////

    printf( "making signature ...\n" );

    rewind( monomial_key_fp );
    rewind( decompressed_xrn_matrix_fp );

    signature_fp = fopen( "signature.xf", "w" );
    if ( signature_fp == NULL ) {
        return -1;
    }

    // Both the type of signature are supported in the generation of zero knowledge proofs.
    // For this code example the xrn_make_signature_symmetric_bytes_wrapper is used, a commented example with
    // the xrn_make_signature_asymmetric_bytes_wrapper is given below.

    if ( XSUCCESS !=
         xrn_make_signature_symmetric_bytes_wrapper( ( uint8_t * ) LOREM_IPSUM_STR, strlen( LOREM_IPSUM_STR ),
                                                     monomial_key_fp, decompressed_xrn_matrix_fp,
                                                     signature_fp, settings ) ) {

        fclose( monomial_key_fp );
        fclose( decompressed_xrn_matrix_fp );
        fclose( signature_fp );

        return -1;

    }

    if ( ( 0 != fclose( monomial_key_fp ) ) || ( 0 != fclose( decompressed_xrn_matrix_fp ) )
         || ( 0 != fclose( signature_fp ) ) ) {
        return -1;
    }

    return 0;

}

int xrn_issuer_commitment_from_signatures_bytes(
 )
{
    //////////////////////////
    // Variable definitions //
    //////////////////////////

    FILE *decompressed_xrn_matrix_fp;
    FILE *monomial_commitment_fp;
    FILE *binomial_commitment_fp;
    FILE *signature_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // make binomial commitment

    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    signature_fp = fopen( "signature.xf", "r" );
    monomial_commitment_fp = fopen( "monomial_commitment.xf", "w" );
    binomial_commitment_fp = fopen( "binomial_commitment.xf", "w" );

    if ( ( decompressed_xrn_matrix_fp == NULL ) || ( signature_fp == NULL )
         || ( monomial_commitment_fp == NULL ) || ( binomial_commitment_fp == NULL ) ) {
        return -1;
    }

    ////////////////////////////////////////////////
    // Generate monomial and binomial commitments //
    ////////////////////////////////////////////////

    if ( XSUCCESS != xrn_make_commitment_from_sym_signatures_bytes_wrapper( ( uint8_t * ) LOREM_IPSUM_STR,      // the signed message 
                                                                            strlen( LOREM_IPSUM_STR ),  // length of the message
                                                                            decompressed_xrn_matrix_fp, // Xoron matrix file pointer
                                                                            signature_fp,       // Xoron binomial key file pointer
                                                                            monomial_commitment_fp,     // Xoron monomial commitment file pointer
                                                                            binomial_commitment_fp,     // Xoron binomial commitment file pointer
                                                                            settings    // runtime settings
          ) ) {
        fclose( decompressed_xrn_matrix_fp );
        fclose( signature_fp );
        fclose( monomial_commitment_fp );
        fclose( binomial_commitment_fp );

        return -1;
    }

    if ( ( 0 != fclose( decompressed_xrn_matrix_fp ) ) || ( 0 != fclose( signature_fp ) )
         || ( 0 != fclose( monomial_commitment_fp ) ) || ( 0 != fclose( binomial_commitment_fp ) ) ) {
        return -1;
    }

    // An alternative way to perform the same computation can be achieved using the xrn_make_commitment_from_sym_signatures function
    // if ( XSUCCESS != xrn_make_commitment_from_sym_signatures_bytes ( (uint8_t *)LOREM_IPSUM_STR, // the signed message 
    //                                                              strlen(LOREM_IPSUM_STR), // the signed message length
    //                                                              xrn_matrix, // xrn_matrix of the type ( xrn_matrix_t * )
    //                                                              signature,    // the signature is of the type ( xsignature_sym_t )
    //                                                              monomial_commitment, // the monomial_commitment is of the type ( xmonomial_commitment_t *)
    //                                                              binomial_commitment, // the monomial_commitment is of the type ( xbinomial_commitment_t *)
    //                                                              settings // runtime settings
    //       ) ) {

    return 0;
}

int xrn_verifier_signature_response_bytes(
 )
{

    FILE *monomial_response_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // make monomial response

    monomial_response_fp = fopen( "monomial_response.xf", "w" );

    if ( XSUCCESS != xrn_make_monomial_response_wrapper( monomial_response_fp,  // Xoron monomial response file pointer
                                                         settings       // runtime settings
          ) ) {
        fclose( monomial_response_fp );
        return -1;
    }

    if ( 0 != fclose( monomial_response_fp ) ) {
        return -1;
    }

    return 0;

}

int xrn_issuer_signature_proof_bytes(
 )
{

    //////////////////////////
    // Variable definitions //
    //////////////////////////

    FILE *decompressed_xrn_matrix_fp;
    FILE *monomial_response_fp;
    FILE *monomial_commitment_fp;
    FILE *signature_fp;
    FILE *monomial_key_fp;
    FILE *monomial_proof_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // make binomial commitment

    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    signature_fp = fopen( "signature.xf", "r" );
    monomial_response_fp = fopen( "monomial_response.xf", "r" );
    monomial_key_fp = fopen( "monomial_key.xf", "r" );
    monomial_proof_fp = fopen( "monomial_proof.xf", "w" );
    monomial_commitment_fp = fopen( "monomial_commitment.xf", "r" );

    if ( ( decompressed_xrn_matrix_fp == NULL ) || ( signature_fp == NULL )
         || ( monomial_response_fp == NULL ) || ( monomial_key_fp == NULL ) || ( monomial_proof_fp == NULL )
         || ( monomial_commitment_fp == NULL ) ) {
        return -1;
    }

    /////////////////////////////
    // Generate monomial proof //
    /////////////////////////////

    if ( XSUCCESS != xrn_make_monomial_proof_from_signature_bytes_wrapper( ( uint8_t * ) LOREM_IPSUM_STR,       // the plain text message
                                                                           strlen( LOREM_IPSUM_STR ),   // the length of the message
                                                                           decompressed_xrn_matrix_fp,  // the Xoron matrix file pointer
                                                                           signature_fp,        // the signature file pointer
                                                                           monomial_key_fp,     // the monomial key file pointer
                                                                           monomial_commitment_fp,      // the monomial commitment file pointer
                                                                           monomial_response_fp,        // the monomial response file pointer
                                                                           monomial_proof_fp,   // the monomial proof file pointer
                                                                           settings     // the run time settings
          ) ) {

        fclose( signature_fp );
        fclose( decompressed_xrn_matrix_fp );
        fclose( monomial_key_fp );
        fclose( monomial_commitment_fp );
        fclose( monomial_response_fp );
        fclose( monomial_proof_fp );

        return -1;

    }

    if ( ( 0 != fclose( signature_fp ) ) || ( 0 != fclose( decompressed_xrn_matrix_fp ) )
         || ( 0 != fclose( monomial_key_fp ) ) || ( 0 != fclose( monomial_commitment_fp ) )
         || ( 0 != fclose( monomial_response_fp ) ) || ( 0 != fclose( monomial_proof_fp ) ) ) {
        return -1;
    }

    // An alternative way to perform the same computation can be achieved using the xrn_make_monomial_proof_from_signature_bytes function
    // if ( XSUCCESS !=
    //      xrn_make_monomial_proof_from_signature_bytes ( 
    //                            ( uint8_t * ) LOREM_IPSUM_STR,       // the plain text message
    //                            strlen( LOREM_IPSUM_STR ),   // the length of the message
    //                            xrn_matrix,   // the Xoron matrix of the type ( xrn_matrix_t * ) 
    //                            signature,  // the signature of the type ( xsignature_sym_t ) 
    //                            monomial_key, // the monomial key of the type ( xmonomial_key_t ) 
    //                            monomial_commitment,  // the monomial commitment of the type ( xmonomial_commitment_t ) 
    //                            monomial_response,  // the monomial response of the type ( xmonomial_response_t ) 
    //                            monomial_proof,  // the monomial proof of the type ( xmonomial_proof_t * ) 
    //                            settings  // the run time settings
    //                           ) ) {

    return 0;

}

int xrn_verifier_signature_check_bytes(
 )
{

    //////////////////////////
    // Variable definitions //
    //////////////////////////

    FILE *decompressed_xrn_matrix_fp;
    FILE *monomial_response_fp;
    FILE *signature_fp;
    FILE *monomial_proof_fp;
    FILE *binomial_commitment_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // make binomial commitment

    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    signature_fp = fopen( "signature.xf", "r" );
    monomial_response_fp = fopen( "monomial_response.xf", "r" );
    monomial_proof_fp = fopen( "monomial_proof.xf", "r" );
    binomial_commitment_fp = fopen( "binomial_commitment.xf", "r" );

    if ( ( decompressed_xrn_matrix_fp == NULL ) || ( signature_fp == NULL )
         || ( monomial_response_fp == NULL ) || ( monomial_proof_fp == NULL )
         || ( binomial_commitment_fp == NULL ) ) {
        return -1;
    }

    //////////////////////////
    // Check monomial proof //
    //////////////////////////

    if ( XSUCCESS != xrn_check_monomial_proof_from_signature_bytes_wrapper( ( uint8_t * ) LOREM_IPSUM_STR,      // the plain text message
                                                                            strlen( LOREM_IPSUM_STR ),  // the length of the message
                                                                            decompressed_xrn_matrix_fp, // the Xoron matrix file pointer
                                                                            signature_fp,       // the signature file pointer
                                                                            binomial_commitment_fp,     // the binomial commitment file pointer
                                                                            monomial_response_fp,       // the monomial response file pointer
                                                                            monomial_proof_fp,  // the monomial proof file pointer
                                                                            settings    // the run time settings
          ) ) {

        fclose( monomial_proof_fp );
        fclose( monomial_response_fp );
        fclose( signature_fp );
        fclose( decompressed_xrn_matrix_fp );
        fclose( binomial_commitment_fp );

        return -1;

    }

    if ( ( 0 != fclose( monomial_proof_fp ) ) || ( 0 != fclose( monomial_response_fp ) )
         || ( 0 != fclose( signature_fp ) ) || ( 0 != fclose( decompressed_xrn_matrix_fp ) )
         || ( 0 != fclose( binomial_commitment_fp ) ) ) {
        return -1;
    }

    // An alternative way to perform the same computation can be achieved using the xrn_check_monomial_proof_from_signature function
    // if ( XSUCCESS != xrn_check_monomial_proof_from_signature( (uint8_t *)LOREM_IPSUM_STR, // the plain text message 
    //                                                  strlen(LOREM_IPSUM_STR),   // the length of the message
    //                                                  xrn_matrix,   // the xrn_matrix is of the type ( xrn_matrix_t * )
    //                                                  signature,      // the signature is of the type ( xsignature_sym_t )
    //                                                  binomial_commitment, // the binomial_commitment is of the type ( xbinomial_commitment_t )
    //                                                  monomial_response,   // the monomial_response is of the type ( xmonomial_response_t )
    //                                                  monomial_proof,      // the monomial_proof is of the type ( xmonomial_proof_t * )
    //                                                  settings     // the run time settings
    //       ) ) {

    return 0;

}

int zero_knowledge_proof_signature_bytes(
 )
{

    /////////////
    // Logging //
    /////////////

    // Set the default logging file streams
    // errors -> stderr
    // warnings -> stdout
    // notifications -> stdout
    // debug -> stdout

    xrn_set_default_log(  );

    // To change the default logging you can use the functions below,
    // where fp is the opened file pointer
    // 
    // xrn_change_error_log( fp )
    // xrn_change_warning_log( fp )
    // xrn_change_notification_log( fp )
    // xrn_change_debug_log( fp )

    printf( "compute keys and signatures ... \n" );

    if ( 0 != generate_keys_and_signatures_bytes(  ) ) {
        return -1;
    }

    printf( "the issuer makes the commitment ... \n" );

    if ( 0 != xrn_issuer_commitment_from_signatures_bytes(  ) ) {
        printf( "error in the commitment\n" );
        return -1;
    }

    printf( "the verifier makes the response ... \n" );

    if ( 0 != xrn_verifier_signature_response_bytes(  ) ) {
        printf( "error in the response\n" );
        return -1;
    }

    printf( "the issuer makes the proof ... \n" );

    if ( 0 != xrn_issuer_signature_proof_bytes(  ) ) {
        printf( "error in the proof\n" );
        return -1;
    }

    printf( "the verifier checks the response ... \n" );

    if ( 0 != xrn_verifier_signature_check_bytes(  ) ) {
        printf( "proof is not valid \n" );
        return -1;
    }

    printf( "proof is valid \n" );

    return 0;

}

